
import pylab as p
import math
from bpsk_modular_bits import modular_bits_en_bpsk
from funciones import generar_bits, sumar_ruido_gaussiano_blanco, detectar_bayesianamente, obtener_muestras_de_entrenamiento, estimar_fase_de_senial_bpsk, encontrar_alphas


# Opciones de grafico
graficar_alpha = False
graficar_A = False
graficar_L = False
graficar_sigma2_W = True

# en cuanto se divide al rango [0, 2pi)
rango_alpha = range(0, 50)
# en cuanto se divide al rango (0, 1]
rango_A = range(1, 50)
# Rango pedido
rango_L = range(2, 18, 2)
# en cuanto se divide al rango (0, 10]
rango_sigma_W = range(1, 50)

# Argumentos
def_lambda_01 = 0.5
def_lambda_11 = 0.5
def_N = 1000
def_alpha_0 = 0
def_alpha_1 = math.pi
def_A = 1
def_L = 8 
def_sigma2_W = 1
def_C_W = def_sigma2_W * p.identity(def_L)
def_P_0 = def_lambda_01
def_P_1 = def_lambda_11

N_ent = 100


def generar_y_detectar(lambda_01=def_lambda_01, lambda_11=def_lambda_11, N=def_N, alpha_0=def_alpha_0,
                        alpha_1=def_alpha_1, A=def_A, L=def_L , sigma2_W=def_sigma2_W, C_W=def_C_W,
                        P_0=def_P_0, P_1=def_P_1):
    generado = generar_bits(lambda_01, lambda_11, N)
    modulado = modular_bits_en_bpsk(generado, alpha_0, alpha_1, A, L)
    modulado_mas_ruido = sumar_ruido_gaussiano_blanco(modulado, sigma2_W)
    entrenamiento = obtener_muestras_de_entrenamiento(N_ent)
    entrenamiento_modulado = modular_bits_en_bpsk(entrenamiento, alpha_0, alpha_1, A, L)   
    entrenamiento_modulado_mas_ruido = sumar_ruido_gaussiano_blanco(entrenamiento_modulado, sigma2_W)
    estimado = []
    for i in range(N_ent):
        estimado_i = estimar_fase_de_senial_bpsk(entrenamiento_modulado_mas_ruido[i * L:(i + 1) * L], A)
        estimado.append(estimado_i)

    alphas = encontrar_alphas(entrenamiento, estimado)
    detectado = []
    error = []
    for i in range(N):
        detectado_i = detectar_bayesianamente(modulado_mas_ruido[i * L:(i + 1) * L], A, alphas[0], alphas[1], C_W, P_0, P_1)
        detectado.append(detectado_i[0])
        error.append(detectado_i[1])
    contador = 0
    for i in range(N):
        if (generado[i] != detectado[i]):
            contador += 1       

    errores = contador / float(N)
    return errores

if (graficar_alpha):
    grafico_alpha = []
    eje = []
    for i in rango_alpha:
        alpha_0_i = float((math.pi / len(rango_alpha)) * i)
        eje.append(alpha_0_i)
        grafico_alpha.append(generar_y_detectar(alpha_0=alpha_0_i))
        
    p.figure(1)
    p.title("f(alpha)")
    p.plot(eje, grafico_alpha)
    p.plot(eje, grafico_alpha, 'o')


if(graficar_A):
    grafico_A = []
    eje = []
    for i in rango_A:
        A_i = float((1.0 / len(rango_A)) * i)
        eje.append(A_i)
        grafico_A.append(generar_y_detectar(A=A_i))
        
    p.figure(2)
    p.title("f(A)")
    p.plot(eje, grafico_A)
    p.plot(eje, grafico_A, 'o')
    
if(graficar_L):
    grafico_L = []
    eje = []
    for i in rango_L:
        L_i = i
        C_W_i = def_sigma2_W * p.identity(L_i)
        eje.append(L_i)
        grafico_L.append(generar_y_detectar(L=L_i, C_W=C_W_i))
        
    p.figure(3)
    p.title("f(L)")
    p.plot(eje, grafico_L)
    p.plot(eje, grafico_L, 'o')
    

if(graficar_sigma2_W):
    grafico_sigma2_W = []
    eje = []
    for i in rango_sigma_W:
        sigma2_W_i = (10.0 / len(rango_sigma_W)) * i
        C_W_i = sigma2_W_i * p.identity(def_L)
        eje.append(sigma2_W_i)
        grafico_sigma2_W.append(generar_y_detectar(sigma2_W=sigma2_W_i, C_W=C_W_i))
        
    p.figure(4)
    p.title("f(sigma2_W)")
    p.plot(eje, grafico_sigma2_W)
    p.plot(eje, grafico_sigma2_W, 'o')

p.show()


